home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sources.misc
- subject: v08i019: roffix - improve overstriking efficiency in nroff output
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Reply-To: wilber@homxc.UUCP
-
- Posting-number: Volume 8, Issue 19
- Submitted-by: wilber@homxc.UUCP
- Archive-name: roffix
-
- I wrote this little hack when I got tired of watching my dot matrix
- printer nearly shake itself to pieces every time it printed out an
- nroff file with lots of underlined and boldfaced words.
-
- Bob Wilber
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 1)."
- # Contents: README MANIFEST roffix.c roffix.1
- # Wrapped by wilber@homxc on Fri Aug 25 16:51:38 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(1180 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- X Roffix
- X
- XThis little program reduces nervous tension for people who use nroff with
- Xsingle-character-at-a-time printers such as dot matrix or daisy wheel printers.
- XIt rearranges the way backspacing is done for overstriking so as to reduce the
- Xnumber of times the print head has to reverse direction. Now when there are a
- Xlot of underlined and boldface words your printer will quickly go zip - zip -
- Xzip instead of slowly go rataratarataratarataratarataratarata.
- X
- XThere's only one source file so a Makefile would be silly. Define LITTLE_STACK
- Xif you have a machine with a small stack limit (less than about 30K bytes).
- XDefine BSD if you're on a BSD system (defaults to System V). You will need
- Xgetopt, which is in the public domain. The "standard" AT&T version of getopt
- Xcan be found in Volume 3 of comp.sources.unix, and various gussied up versions
- Xare also available.
- X
- XApparently there's an nroff clone running under MS-DOS that's already smart
- Xabout backspacing, so for it this program will have little or no effect.
- X
- XRoffix is in the public domain and is not a trademark of anybody.
- X
- XReport bugs to wilber@homxc.att.com, with a *small* nroff file that exhibits
- Xthe bug.
- END_OF_FILE
- if test 1180 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(34 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- XREADME
- XMANIFEST
- Xroffix.c
- Xroffix.1
- END_OF_FILE
- if test 34 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test -f 'roffix.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'roffix.c'\"
- else
- echo shar: Extracting \"'roffix.c'\" \(9357 characters\)
- sed "s/^X//" >'roffix.c' <<'END_OF_FILE'
- X/*
- Xroffix - improve overstriking efficiency in output of nroff
- X
- XUsage: nroff -Tlp file | roffix | lp
- XSee man page for details.
- X
- XThis program is in the public domain.
- X
- XSend bugs to: wilber@homxc.att.com
- X(Make sure you send a *small* nroff file that exhibits the problem.)
- X*/
- X
- X#include <errno.h>
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X/* Can you say "gratuitous incompatibility?" */
- X#ifdef BSD
- X#include <strings.h>
- X#else
- X#include <string.h>
- X#endif
- X
- Xextern int getopt();
- Xextern char *optarg;
- Xextern int optind;
- X
- Xextern int errno;
- Xextern char *sys_errlist[];
- Xextern int sys_nerr;
- Xstatic char errmsg[30];
- X
- X/* #define LITTLE_STACK */
- X /* Define if your machine has a small stack ( <~ 30K ) */
- X
- X#define MAX_LINE 1000
- X /* Maximum number of characters on a line. */
- X
- X#define MAX_OVERSTRIKE 20
- X /* Maximum number of characters overprinted in a single position */
- X
- X#define SINGLE_LIMIT 4
- X /* Default for single_limit, the number of non-overstruck characters
- X that can be between two sequences of overstruck characters and
- X still have the backspacing for the two sequences be done at once.
- X E.g., with single_limit = 2,
- X _^Hf_^Ho_^Ho, _^Hb_^Ha_^Hr & _^Hq_^Hu_^Hu_^Hx
- X becomes
- X foo, bar^H^H^H^H^H^H^H^H___ ___ & quux^H^H^H^H____
- X but with single_limit >= 3 it becomes
- X foo, bar & quux^H^H^H^H^H^H^H^H^H^H^H^H^H^H^H___ ___ ____
- X */
- X
- Xtypedef struct
- X {
- X int bx;
- X int max_bx;
- X char buffer[MAX_LINE][MAX_OVERSTRIKE];
- X char next_pos[MAX_LINE];
- X } LineBuffer;
- X
- X#define ALT_START '\016'
- X /* Start alternate character set. */
- X#define ALT_END '\017'
- X /* End alternate character set. */
- X#define ESC '\033'
- X
- Xextern void do_it();
- Xextern void dump_buffer();
- X
- Xstatic int error_cnt = 0;
- X
- Xchar* errormsg()
- X{
- X if (errno <= sys_nerr) return sys_errlist[errno];
- X sprintf(errmsg, "error code %d", errno);
- X return errmsg;
- X}
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar *argv[];
- X{
- X char *in_name;
- X FILE *outfile, *infile;
- X int opt;
- X int single_limit = SINGLE_LIMIT;
- X
- X outfile = stdout;
- X while ((opt = getopt(argc, argv, "?o:s:")) != EOF)
- X {
- X switch (opt)
- X {
- X case 'o':
- X if (!(outfile = fopen(optarg, "w")))
- X {
- X fprintf(stderr, "roffix: Open of %s failed.\n%s\n", optarg,
- X errormsg());
- X exit(1);
- X }
- X break;
- X case 's':
- X single_limit = atoi(optarg);
- X break;
- X case '?':
- X default:
- X fputs("usage: roffix [ -o outfile ] [ -s count ] infile ...\n",
- X stderr);
- X exit(1);
- X }
- X }
- X if (optind < argc)
- X {
- X for (; optind < argc; optind++)
- X {
- X in_name = argv[optind];
- X if (access(in_name, 04) || !(infile = fopen(in_name, "r")))
- X {
- X fprintf(stderr, "roffix: Open of %s failed.\n%s\n", in_name,
- X errormsg());
- X error_cnt++;
- X }
- X else do_it(in_name, infile, outfile, single_limit);
- X }
- X }
- X else do_it("stdin", stdin, outfile, single_limit);
- X exit(error_cnt);
- X}
- X
- Xchar* lc2str(i)
- Xint i;
- X{
- X static char buf[30];
- X int j = i / 2;
- X sprintf(buf, "line %d", j);
- X if (i > 2*j) strcat(buf, " 1/2");
- X return buf;
- X}
- X
- Xvoid do_it(in_fname, infile, outfile, single_limit)
- Xchar *in_fname;
- XFILE *infile, *outfile;
- Xint single_limit;
- X{
- X register int inch;
- X#ifdef LITTLE_STACK
- X static
- X#endif
- X LineBuffer lb;
- X int line_count; /* Counts half-lines, not full lines. */
- X int left_error; /* Used to ensure that we print the error about */
- X int right_error; /* backspacing before the first column or forward */
- X /* spacing after the last column only once per line. */
- X int overstrike_error; /* Like above but for exceeding MAX_OVERSTRIKE. */
- X int crossing_error; /* Like above but for backspace crossing a tab. */
- X char break_char; /* The character that caused the last dump of the
- X buffer. */
- X
- X for (lb.bx = 0; lb.bx < MAX_LINE; lb.bx++) lb.next_pos[lb.bx] = 0;
- X lb.bx = lb.max_bx = 0;
- X line_count = 2;
- X crossing_error = left_error = right_error = overstrike_error = 0;
- X break_char = '\n';
- X
- X/* lb.bx keeps track of nroff's notion of where the print head is relative
- X to the start of the current buffer. When lb.bx is < 0 we output backspaces
- X and normal characters immediately, when lb.bx >= 0 printable characters
- X are stuffed into "buffer" for processing by dump_buffer.
- X*/
- X
- X while ((inch = getc(infile)) != EOF)
- X {
- X switch (inch)
- X {
- X case '\f':
- X case '\n':
- X case '\r':
- X dump_buffer(outfile, &lb, single_limit, 0);
- X break_char = '\n'; /* All are "new lines" for our purposes. */
- X putc(inch, outfile);
- X if (inch != '\r') line_count += 2;
- X crossing_error = left_error = right_error = overstrike_error = 0;
- X break;
- X case '\t':
- X if (lb.bx < lb.max_bx && !crossing_error)
- X {
- X fprintf(stderr,
- X "roffix: warning: %s, %s: Crossing a tab with a backspace.\n",
- X in_fname, lc2str(line_count));
- X crossing_error = 1;
- X error_cnt++;
- X }
- X dump_buffer(outfile, &lb, single_limit, 1);
- X break_char = inch;
- X putc(inch, outfile);
- X break;
- X case ALT_START:
- X /* Alternate character set enabled. Just dump out the
- X characters "as is" until the normal character set is
- X re-enabled. */
- X dump_buffer(outfile, &lb, single_limit, 1);
- X break_char = inch;
- X putc(inch, outfile);
- X while ((inch = getc(infile)) != ALT_END)
- X {
- X if (inch == EOF)
- X {
- X fprintf(stderr,
- X "roffix: warning: %s: File ended in alternate character set mode.\n",
- X in_fname);
- X putc(ALT_END, outfile);
- X return;
- X }
- X putc(inch, outfile);
- X }
- X putc(inch, outfile);
- X break;
- X case ESC:
- X dump_buffer(outfile, &lb, single_limit, 1);
- X break_char = inch;
- X putc(inch, outfile);
- X if ((inch = getc(infile)) == EOF) return;
- X putc(inch, outfile);
- X switch (inch)
- X {
- X case '9': line_count += 3; /* Forward 1/2 line feed. */
- X case '7': line_count--; /* Reverse line feed. */
- X case '8': line_count--; /* Reverse 1/2 line feed. */
- X crossing_error = left_error = right_error = overstrike_error = 0;
- X break;
- X default:
- X break;
- X }
- X break;
- X case '\v': /* Alternative to ESC 7 */
- X dump_buffer(outfile, &lb, single_limit, 1);
- X break_char = inch;
- X putc(inch, outfile);
- X line_count -= 2;
- X crossing_error = left_error = right_error = overstrike_error = 0;
- X break;
- X case '\b':
- X lb.bx--;
- X if (lb.bx < 0)
- X {
- X putc(inch, outfile);
- X if (break_char == '\n' && !left_error)
- X {
- X fprintf(stderr,
- X "roffix: warning: %s, %s: Backspacing to left of first column.\n",
- X in_fname, lc2str(line_count));
- X left_error = 1;
- X error_cnt++;
- X }
- X else if (break_char == '\t' && !crossing_error)
- X {
- X fprintf(stderr,
- X "roffix: warning: %s, %s: Crossing a tab with a backspace.\n",
- X in_fname, lc2str(line_count));
- X crossing_error = 1;
- X error_cnt++;
- X }
- X }
- X break;
- X default:
- X if (isprint(inch))
- X {
- X if (lb.bx >= 0)
- X {
- X if (lb.bx >= MAX_LINE)
- X {
- X if (!right_error)
- X {
- X fprintf(stderr,
- X "roffix: warning: %s, %s: Exceeded line limit of %d characters.\n",
- X in_fname, lc2str(line_count), MAX_LINE);
- X right_error = 1;
- X error_cnt++;
- X }
- X }
- X else
- X {
- X if (inch != ' ')
- X {
- X if (lb.next_pos[lb.bx] >= MAX_OVERSTRIKE)
- X {
- X if (!overstrike_error)
- X {
- X fprintf(stderr,
- X "roffix: warning: %s, %s: Exceeded overstrike limit of %d.\n",
- X in_fname, lc2str(line_count),
- X MAX_OVERSTRIKE);
- X overstrike_error = 1;
- X error_cnt++;
- X }
- X }
- X else lb.buffer[lb.bx][lb.next_pos[lb.bx]++] = inch;
- X }
- X if (++lb.bx > lb.max_bx) lb.max_bx = lb.bx;
- X }
- X }
- X else /* The print head is to the left of the leftmost position
- X in the current buffer, so send out character immediately.
- X */
- X {
- X putc(inch, outfile);
- X ++lb.bx;
- X }
- X }
- X else /* A funny character. Ship it out and hope it works. */
- X {
- X dump_buffer(outfile, &lb, single_limit, 1);
- X break_char = inch;
- X putc(inch, outfile);
- X }
- X }
- X }
- X if (lb.max_bx > 0)
- X dump_buffer(outfile, &lb, single_limit, 0);
- X return;
- X}
- X
- Xvoid dump_buffer(outfile, lbP, single_lmt, fix_final_pos)
- XFILE* outfile;
- XLineBuffer *lbP;
- Xint single_lmt;
- Xint fix_final_pos; /* If true, make sure actual printhead finishes where
- X nroff thinks it should. */
- X{
- X register int px = 0;
- X register int qx, rx, sx;
- X int snglecnt;
- X /* Bring the print head up to where it's supposed to be for
- X dumping the buffer. */
- X for (sx = lbP->bx; sx < 0; sx++) putc(' ', outfile);
- X while (1)
- X {
- X while (px < lbP->max_bx && lbP->next_pos[px] <= 1)
- X {
- X if (lbP->next_pos[px] == 0) putc(' ', outfile);
- X else putc(lbP->buffer[px][--lbP->next_pos[px]], outfile);
- X px++;
- X }
- X if (px >= lbP->max_bx) break;
- X qx = px + 1;
- X while (1)
- X {
- X while (qx < lbP->max_bx && lbP->next_pos[qx] > 1) qx++;
- X if (qx >= lbP->max_bx) break;
- X snglecnt = 1;
- X for (rx = qx + 1;
- X rx < lbP->max_bx && lbP->next_pos[rx] <= 1 &&
- X snglecnt <= single_lmt;
- X rx++) snglecnt++;
- X if (rx >= lbP->max_bx || snglecnt > single_lmt) break;
- X qx = rx + 1;
- X }
- X for (sx = px; sx < qx; sx++)
- X {
- X if (lbP->next_pos[sx] == 0) putc(' ', outfile);
- X else putc(lbP->buffer[sx][--lbP->next_pos[sx]], outfile);
- X }
- X for (sx = px; sx < qx; sx++) putc('\b', outfile);
- X }
- X if (fix_final_pos)
- X for (sx = lbP->bx; sx < lbP->max_bx; sx++) putc('\b', outfile);
- X lbP->bx = lbP->max_bx = 0;
- X}
- END_OF_FILE
- if test 9357 -ne `wc -c <'roffix.c'`; then
- echo shar: \"'roffix.c'\" unpacked with wrong size!
- fi
- # end of 'roffix.c'
- fi
- if test -f 'roffix.1' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'roffix.1'\"
- else
- echo shar: Extracting \"'roffix.1'\" \(3560 characters\)
- sed "s/^X//" >'roffix.1' <<'END_OF_FILE'
- X.TH ROFFIX 1
- X.SH NAME
- Xroffix \(mi improve overstriking efficiency in output of nroff
- X.SH SYNOPSIS
- X\fBroffix\fP [ \(mi\fBs\fP count ] [ \(mi\fBo\fP outfile ] file1 ...
- X.SH DESCRIPTION
- XThe text formatting program \fInroff\fP(1) produces output
- Xthat is very unpleasant to print on dot matrix or daisy wheel printers.
- X\fINroff\fP produces an underlined word such as ``\o'f_'\o'o_'\o'o_'''
- Xby generating the output
- X``_^Hf_^Ho_^Ho'', which causes a print head to reverse direction six times.
- X(Here ``^H'' means ``backspace.'')
- XThis is slow, noisy, and probably causes excessive wear on the print head
- Xdrive.
- XWhen the \fBboldface\fP font is achieved by overstriking the situation is even
- Xworse.
- X\fIRoffix\fP is a post-filter for \fInroff\fP that fixes this problem by
- Xchanging ``_^Hf_^Ho_^Ho'' to
- X``foo^H^H^H___'', which causes only two reversals of the print head.
- X.PP
- XFiles listed on the command line are read as input, unless there are none,
- Xin which case standard input is used.
- XThe input files should have been generated by \fInroff\fP.
- XThe output goes to \fIoutfile\fP if the \(mi\fBo\fP option is used,
- Xotherwise to standard output.
- X.PP
- XThe \fIcount\fP given with the \(mi\fBs\fP option requires a bit of
- Xexplanation.
- XSuppose we want to output
- X.ti +4m
- X\o'f_'\o'o_'\o'o_', \o'b_'\o'a_'\o'r_'
- X.br
- XThis is best handled as a single unit, i.e.,
- X.ti +4m
- Xfoo, bar^H^H^H^H^H^H^H^H___ ___
- X.br
- XIf the spacing is greater, e.g.,
- X.ti +4m
- X\o'f_'\o'o_'\o'o_', \o'b_'\o'a_'\o'r_'
- X.br
- Xit's probably faster to backspace separately for each word, i.e.,
- X.ti +4m
- Xfoo^H^H^H___, bar^H^H^H___
- X.br
- X\fICount\fP is the maximum number of consecutive non-overstruck characters that
- Xcan be between two groups of overstruck characters and still have the
- Xbackspacing for both groups be done at once.
- XThe default for \fIcount\fP is 4.
- X.PP
- XThe backspacing for the characters that precede a control character
- Xor escape sequence is always
- Xdone separately from the backspacing for the characters that follow.
- XThe control character or escape sequence itself is always output verbatim,
- Xand is not involved in backspace processing.
- XAn escape sequence is always assumed to consist of ESC followed by one
- Xcharacter.
- XThe characters SO (ASCII \\016) and SI (ASCII \\017) are assumed to begin
- Xand end a sequence of characters from an alternate character set.
- XThey and the characters they delimit are output verbatim without any
- Xprocessing of imbedded backspaces.
- X\fIRoffix\fP recognizes the following control characters and escape sequences
- Xfor the purpose of keeping track of the current line number:
- Xnew line, return, form feed, ESC 7 (reverse line feed), ESC 8 (reverse half
- Xline feed), ESC 9 (forward half line feed), and VT (ASCII \\013 \(mi
- Xinterpreted as reverse line feed for compatibility with old programs).
- X.PP
- XWarnings are issued if there is any backspacing over a tab, new line, return,
- Xor form feed.
- XBackspacing over other control characters is done without warnings;
- Xit is assumed \fInroff\fP knows what it's doing.
- X.PP
- XThe return value of \fIroffix\fP is the number of errors encountered (0 if
- Xno errors).
- X.SH EXAMPLE
- Xnroff \(miTlp \(miman roffix.1 | roffix | lp
- X.SH SEE ALSO
- X\fInroff\fP(1), \fIcol\fP(1)
- X.SH BUGS
- X\fIRoffix\fP reverses the order in which characters are overstruck.
- XThis should not matter on any normal hardcopy printer.
- XMulti-character escape sequences may get garbled.
- XBackspacing over
- Xcontrol sequences that make the printer space horizontally or
- Xvertically in strange ways will probably confuse \fIroffix\fP.
- END_OF_FILE
- if test 3560 -ne `wc -c <'roffix.1'`; then
- echo shar: \"'roffix.1'\" unpacked with wrong size!
- fi
- # end of 'roffix.1'
- fi
- echo shar: End of archive 1 \(of 1\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have the archive.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-